#include "./BSP/RS485/rs485.h"
#include "./SYSTEM/delay/delay.h"

/* -------------------------------------------- 全局变量定义 ------------------------------------------- */

/* RS485_1 变量 */
UART_HandleTypeDef g_rs485_1_handler;    /* RS485_1控制句柄(串口) */

#ifdef RS485_EN_RX /* 如果使能了接收 */
uint8_t g_RS485_1_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节 */
uint8_t g_RS485_1_rx_cnt = 0;            /* 接收到的数据长度 */
#endif

/* RS485_2 变量 */
UART_HandleTypeDef g_rs485_2_handler;    /* RS485_2控制句柄(串口) */

#ifdef RS485_EN_RX /* 如果使能了接收 */
uint8_t g_RS485_2_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节 */
uint8_t g_RS485_2_rx_cnt = 0;            /* 接收到的数据长度 */
#endif

/* RS485_3 变量 */
UART_HandleTypeDef g_rs485_3_handler;    /* RS485_3控制句柄(串口) */

#ifdef RS485_EN_RX /* 如果使能了接收 */
uint8_t g_RS485_3_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节 */
uint8_t g_RS485_3_rx_cnt = 0;            /* 接收到的数据长度 */
#endif

/* -------------------------------------------- 中断处理函数 ------------------------------------------- */

#ifdef RS485_EN_RX /* 如果使能了接收 */

/* RS485_1 中断处理函数 */
void RS485_1_UX_IRQHandler(void)
{
    uint8_t res;

    if ((__HAL_UART_GET_FLAG(&g_rs485_1_handler, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */
    {
        HAL_UART_Receive(&g_rs485_1_handler, &res, 1, 1000);

        if (g_RS485_1_rx_cnt < RS485_REC_LEN)        /* 缓冲区未满 */
        {
            g_RS485_1_rx_buf[g_RS485_1_rx_cnt] = res;/* 记录接收到的值 */
            g_RS485_1_rx_cnt++;                      /* 接收数据增加1 */
        }
    }
}

/* RS485_2 中断处理函数 */
void RS485_2_UX_IRQHandler(void)
{
    uint8_t res;

    if ((__HAL_UART_GET_FLAG(&g_rs485_2_handler, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */
    {
        HAL_UART_Receive(&g_rs485_2_handler, &res, 1, 1000);

        if (g_RS485_2_rx_cnt < RS485_REC_LEN)        /* 缓冲区未满 */
        {
            g_RS485_2_rx_buf[g_RS485_2_rx_cnt] = res;/* 记录接收到的值 */
            g_RS485_2_rx_cnt++;                      /* 接收数据增加1 */
        }
    }
}

/* RS485_3 中断处理函数 */
void RS485_3_UX_IRQHandler(void)
{
    uint8_t res;

    if ((__HAL_UART_GET_FLAG(&g_rs485_3_handler, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */
    {
        HAL_UART_Receive(&g_rs485_3_handler, &res, 1, 1000);

        if (g_RS485_3_rx_cnt < RS485_REC_LEN)        /* 缓冲区未满 */
        {
            g_RS485_3_rx_buf[g_RS485_3_rx_cnt] = res;/* 记录接收到的值 */
            g_RS485_3_rx_cnt++;                      /* 接收数据增加1 */
        }
    }
}

#endif

/* -------------------------------------------- 函数实现 ----------------------------------------------- */

/**
 * @brief       RS485_1初始化函数
 * @note        该函数主要是初始化串口1
 * @param[in]   baudrate 波特率, 根据自己需要设置波特率值
 * @return      无
 */
void rs485_1_init(uint32_t baudrate)
{
    /* IO 及 时钟配置 */
    RS485_1_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_1_RE 脚时钟 */
    RS485_1_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */
    RS485_1_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */
    RS485_1_UX_CLK_ENABLE();      /* 使能 串口 时钟 */

    GPIO_InitTypeDef gpio_initure;
    gpio_initure.Pin = RS485_1_TX_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_AF_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    gpio_initure.Alternate = GPIO_AF7_USART1;               /* 复用为串口1 */
    HAL_GPIO_Init(RS485_1_TX_GPIO_PORT, &gpio_initure);     /* 串口TX 脚 模式设置 */

    gpio_initure.Pin = RS485_1_RX_GPIO_PIN;
    HAL_GPIO_Init(RS485_1_RX_GPIO_PORT, &gpio_initure);     /* 串口RX 脚 必须设置成输入模式 */

    gpio_initure.Pin = RS485_1_RE_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_1_RE_GPIO_PORT, &gpio_initure);     /* RS485_1_RE 脚 模式设置 */

    /* USART 初始化设置 */
    g_rs485_1_handler.Instance = RS485_1_UX;                /* 选择485对应的串口 */
    g_rs485_1_handler.Init.BaudRate = baudrate;             /* 波特率 */
    g_rs485_1_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
    g_rs485_1_handler.Init.StopBits = UART_STOPBITS_1;      /* 一个停止位 */
    g_rs485_1_handler.Init.Parity = UART_PARITY_NONE;       /* 无奇偶校验位 */
    g_rs485_1_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
    g_rs485_1_handler.Init.Mode = UART_MODE_TX_RX;          /* 收发模式 */
    HAL_UART_Init(&g_rs485_1_handler);                      /* 使能对应的串口, 但会调用MSp */
    __HAL_UART_DISABLE_IT(&g_rs485_1_handler, UART_IT_TC);

#if RS485_EN_RX /* 如果使能了接收 */
    /* 使能接收中断 */
    __HAL_UART_ENABLE_IT(&g_rs485_1_handler, UART_IT_RXNE); /* 开启接收中断 */
    HAL_NVIC_EnableIRQ(RS485_1_UX_IRQn);                    /* 使能USART1中断 */
    HAL_NVIC_SetPriority(RS485_1_UX_IRQn, 3, 3);            /* 抢占优先级3，子优先级3 */
#endif

    RS485_1_RE(0); /* 默认为接收模式 */
}

/**
 * @brief       RS485_2初始化函数
 * @note        该函数主要是初始化串口3
 * @param[in]   baudrate 波特率, 根据自己需要设置波特率值
 * @return      无
 */
void rs485_2_init(uint32_t baudrate)
{
    /* IO 及 时钟配置 */
    RS485_2_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_2_RE 脚时钟 */
    RS485_2_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */
    RS485_2_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */
    RS485_2_UX_CLK_ENABLE();      /* 使能 串口 时钟 */

    GPIO_InitTypeDef gpio_initure;
    gpio_initure.Pin = RS485_2_TX_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_AF_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    gpio_initure.Alternate = GPIO_AF7_USART3;               /* 复用为串口3 */
    HAL_GPIO_Init(RS485_2_TX_GPIO_PORT, &gpio_initure);     /* 串口TX 脚 模式设置 */

    gpio_initure.Pin = RS485_2_RX_GPIO_PIN;
    HAL_GPIO_Init(RS485_2_RX_GPIO_PORT, &gpio_initure);     /* 串口RX 脚 必须设置成输入模式 */

    gpio_initure.Pin = RS485_2_RE_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_2_RE_GPIO_PORT, &gpio_initure);     /* RS485_2_RE 脚 模式设置 */

    /* USART 初始化设置 */
    g_rs485_2_handler.Instance = RS485_2_UX;                /* 选择485对应的串口 */
    g_rs485_2_handler.Init.BaudRate = baudrate;             /* 波特率 */
    g_rs485_2_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
    g_rs485_2_handler.Init.StopBits = UART_STOPBITS_1;      /* 一个停止位 */
    g_rs485_2_handler.Init.Parity = UART_PARITY_NONE;       /* 无奇偶校验位 */
    g_rs485_2_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
    g_rs485_2_handler.Init.Mode = UART_MODE_TX_RX;          /* 收发模式 */
    HAL_UART_Init(&g_rs485_2_handler);                      /* 使能对应的串口, 但会调用MSp */
    __HAL_UART_DISABLE_IT(&g_rs485_2_handler, UART_IT_TC);

#if RS485_EN_RX /* 如果使能了接收 */
    /* 使能接收中断 */
    __HAL_UART_ENABLE_IT(&g_rs485_2_handler, UART_IT_RXNE); /* 开启接收中断 */
    HAL_NVIC_EnableIRQ(RS485_2_UX_IRQn);                    /* 使能USART3中断 */
    HAL_NVIC_SetPriority(RS485_2_UX_IRQn, 3, 3);            /* 抢占优先级3，子优先级3 */
#endif

    RS485_2_RE(0); /* 默认为接收模式 */
}

/**
 * @brief       RS485_3初始化函数
 * @note        该函数主要是初始化串口2
 * @param[in]   baudrate 波特率, 根据自己需要设置波特率值
 * @return      无
 */
void rs485_3_init(uint32_t baudrate)
{
    /* IO 及 时钟配置 */
    RS485_3_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_3_RE 脚时钟 */
    RS485_3_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */
    RS485_3_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */
    RS485_3_UX_CLK_ENABLE();      /* 使能 串口 时钟 */

    GPIO_InitTypeDef gpio_initure;
    gpio_initure.Pin = RS485_3_TX_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_AF_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    gpio_initure.Alternate = GPIO_AF7_USART2;               /* 复用为串口2 */
    HAL_GPIO_Init(RS485_3_TX_GPIO_PORT, &gpio_initure);     /* 串口TX 脚 模式设置 */

    gpio_initure.Pin = RS485_3_RX_GPIO_PIN;
    HAL_GPIO_Init(RS485_3_RX_GPIO_PORT, &gpio_initure);     /* 串口RX 脚 必须设置成输入模式 */

    gpio_initure.Pin = RS485_3_RE_GPIO_PIN;
    gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_initure.Pull = GPIO_PULLUP;
    gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(RS485_3_RE_GPIO_PORT, &gpio_initure);     /* RS485_3_RE 脚 模式设置 */

    /* USART 初始化设置 */
    g_rs485_3_handler.Instance = RS485_3_UX;                /* 选择485对应的串口 */
    g_rs485_3_handler.Init.BaudRate = baudrate;             /* 波特率 */
    g_rs485_3_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
    g_rs485_3_handler.Init.StopBits = UART_STOPBITS_1;      /* 一个停止位 */
    g_rs485_3_handler.Init.Parity = UART_PARITY_NONE;       /* 无奇偶校验位 */
    g_rs485_3_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
    g_rs485_3_handler.Init.Mode = UART_MODE_TX_RX;          /* 收发模式 */
    HAL_UART_Init(&g_rs485_3_handler);                      /* 使能对应的串口, 但会调用MSp */
    __HAL_UART_DISABLE_IT(&g_rs485_3_handler, UART_IT_TC);

#if RS485_EN_RX /* 如果使能了接收 */
    /* 使能接收中断 */
    __HAL_UART_ENABLE_IT(&g_rs485_3_handler, UART_IT_RXNE); /* 开启接收中断 */
    HAL_NVIC_EnableIRQ(RS485_3_UX_IRQn);                    /* 使能USART2中断 */
    HAL_NVIC_SetPriority(RS485_3_UX_IRQn, 3, 3);            /* 抢占优先级3，子优先级3 */
#endif

    RS485_3_RE(0); /* 默认为接收模式 */
}

/**
 * @brief       RS485_1发送len个字节
 * @param[in]   buf     发送区首地址
 * @param[in]   len     发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)
 * @return      无
 */
void rs485_1_send_data(uint8_t *buf, uint8_t len)
{
    RS485_1_RE(1);                                            /* 进入发送模式 */
    HAL_UART_Transmit(&g_rs485_1_handler, buf, len, 1000);    /* 串口1发送数据 */
    g_RS485_1_rx_cnt = 0;
    RS485_1_RE(0); /* 进入接收模式 */
}

/**
 * @brief       RS485_2发送len个字节
 * @param[in]   buf     发送区首地址
 * @param[in]   len     发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)
 * @return      无
 */
void rs485_2_send_data(uint8_t *buf, uint8_t len)
{
    RS485_2_RE(1);                                            /* 进入发送模式 */
    HAL_UART_Transmit(&g_rs485_2_handler, buf, len, 1000);    /* 串口3发送数据 */
    g_RS485_2_rx_cnt = 0;
    RS485_2_RE(0); /* 进入接收模式 */
}

/**
 * @brief       RS485_3发送len个字节
 * @param[in]   buf     发送区首地址
 * @param[in]   len     发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)
 * @return      无
 */
void rs485_3_send_data(uint8_t *buf, uint8_t len)
{
    RS485_3_RE(1);                                            /* 进入发送模式 */
    HAL_UART_Transmit(&g_rs485_3_handler, buf, len, 1000);    /* 串口2发送数据 */
    g_RS485_3_rx_cnt = 0;
    RS485_3_RE(0); /* 进入接收模式 */
}

/**
 * @brief       RS485_1查询接收到的数据
 * @param[out]  buf     接收缓冲区首地址
 * @param[out]  len     接收到的数据长度
 *   @arg               0   表示没有接收到任何数据
 *   @arg               其他 表示接收到的数据长度
 * @return      无
 */
void rs485_1_receive_data(uint8_t *buf, uint8_t *len)
{
    uint8_t rxlen = g_RS485_1_rx_cnt;
    uint8_t i = 0;
    *len = 0;     /* 默认为0 */
    delay_ms(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */

    if (rxlen == g_RS485_1_rx_cnt && rxlen) /* 接收到了数据,且接收完成了 */
    {
        for (i = 0; i < rxlen; i++)
        {
            buf[i] = g_RS485_1_rx_buf[i];
        }

        *len = g_RS485_1_rx_cnt; /* 记录本次数据长度 */
        g_RS485_1_rx_cnt = 0;    /* 清零 */
    }
}

/**
 * @brief       RS485_2查询接收到的数据
 * @param[out]  buf     接收缓冲区首地址
 * @param[out]  len     接收到的数据长度
 *   @arg               0   表示没有接收到任何数据
 *   @arg               其他 表示接收到的数据长度
 * @return      无
 */
void rs485_2_receive_data(uint8_t *buf, uint8_t *len)
{
    uint8_t rxlen = g_RS485_2_rx_cnt;
    uint8_t i = 0;
    *len = 0;     /* 默认为0 */
    delay_ms(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */

    if (rxlen == g_RS485_2_rx_cnt && rxlen) /* 接收到了数据,且接收完成了 */
    {
        for (i = 0; i < rxlen; i++)
        {
            buf[i] = g_RS485_2_rx_buf[i];
        }

        *len = g_RS485_2_rx_cnt; /* 记录本次数据长度 */
        g_RS485_2_rx_cnt = 0;    /* 清零 */
    }
}

/**
 * @brief       RS485_3查询接收到的数据
 * @param[out]  buf     接收缓冲区首地址
 * @param[out]  len     接收到的数据长度
 *   @arg               0   表示没有接收到任何数据
 *   @arg               其他 表示接收到的数据长度
 * @return      无
 */
void rs485_3_receive_data(uint8_t *buf, uint8_t *len)
{
    uint8_t rxlen = g_RS485_3_rx_cnt;
    uint8_t i = 0;
    *len = 0;     /* 默认为0 */
    delay_ms(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */

    if (rxlen == g_RS485_3_rx_cnt && rxlen) /* 接收到了数据,且接收完成了 */
    {
        for (i = 0; i < rxlen; i++)
        {
            buf[i] = g_RS485_3_rx_buf[i];
        }

        *len = g_RS485_3_rx_cnt; /* 记录本次数据长度 */
        g_RS485_3_rx_cnt = 0;    /* 清零 */
    }
}
